package lc.elensliu.ipcclient;

import android.app.Activity;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.os.Handler;
import android.os.IBinder;
import android.os.Message;
import android.os.Messenger;
import android.os.RemoteException;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.EditText;
import android.widget.TextView;

import com.ipc.aidl.implement.Constants;
import com.ipc.aidl.implement.IMessageBinder;
import com.ipc.aidl.implement.IMessageCallback;

import org.w3c.dom.Text;

import java.lang.ref.WeakReference;
import java.util.List;

public class MainActivity extends AppCompatActivity {


    static class MyHandler extends Handler {

        private final WeakReference<Activity> mActivity;
        private TextView messageTx;

        public MyHandler (Activity activity) {

            mActivity = new WeakReference (activity);
        }

        @Override
        public void handleMessage (Message msg) {
            super.handleMessage (msg);

            Activity activity = mActivity.get ();
            if (msg.what == Constants.GET_RESULT && activity != null) {

                String message = msg.getData ()
                                    .getString (Constants.MSG_KEY);
                messageTx = (TextView) activity.findViewById (R.id.messageTx);
                messageTx.setText (message);
            }

        }
    }


    private Messenger mService;
    private Messenger messenger;
    private boolean isBinding = false;

    private IMessageBinder aidlInterface;
    private boolean isAidlBinding = false;


    private ServiceConnection mConnection = new ServiceConnection () {
        @Override
        public void onServiceConnected (ComponentName name, IBinder service) {

            mService = new Messenger (service);
            isBinding = true;
        }

        @Override
        public void onServiceDisconnected (ComponentName name) {
            mService = null;
            isBinding = false;
        }
    };

    private ServiceConnection aidlConnection = new ServiceConnection () {
        @Override
        public void onServiceConnected (ComponentName name, IBinder service) {

            aidlInterface = IMessageBinder.Stub.asInterface (service);
            isAidlBinding = true;
        }

        @Override
        public void onServiceDisconnected (ComponentName name) {

            aidlInterface = null;
            isAidlBinding = false;
        }
    };


    private EditText messageEt;

    @Override
    protected void onCreate (Bundle savedInstanceState) {
        super.onCreate (savedInstanceState);
        setContentView (R.layout.activity_main);
        messageEt = (EditText) findViewById (R.id.messageEt);
        messenger = new Messenger (new MyHandler (this));
    }

    @Override
    protected void onDestroy () {
        super.onDestroy ();
        if (isBinding) {
            unbindService (mConnection);
        }
        if (isAidlBinding) {

            try {
                aidlInterface.unregisterCallback (messageCallback2);
            } catch (RemoteException e) {
                e.printStackTrace ();
            }
            unbindService (aidlConnection);
        }

    }

    public void onConnect (View view) {

        Intent intent = new Intent (Constants.SERVICE_ACTION);
        Intent eintent = new Intent (getExplicitIntent (this,
                                                        intent));
        bindService (eintent,
                     mConnection,
                     BIND_AUTO_CREATE);
    }

    public void onConnectAIDL (View view) {

        Intent intent = new Intent (Constants.AIDL_SERVICE_ACTION);
        Intent eintent = new Intent (getExplicitIntent (this,
                                                        intent));
        bindService (eintent,
                     aidlConnection,
                     BIND_AUTO_CREATE);
    }


    public void sendMsg (View view) {

        if (isBinding) {

            String msg = messageEt.getText ()
                                  .toString ();

            Message message = Message.obtain (null,
                                              Constants.SEND_MSG);
            message.replyTo = messenger;

            Bundle bundle = new Bundle ();
            bundle.putString (Constants.MSG_KEY,
                              msg);
            message.setData (bundle);
            try {
                mService.send (message);
            } catch (RemoteException e) {
                e.printStackTrace ();
            }

        }
    }

    public void sendMsgAIDL (View view) {

        if (isAidlBinding) {

            String msg = messageEt.getText ()
                                  .toString ();


            try {
                aidlInterface.registerCallback (messageCallback2);
                aidlInterface.sendMessage (msg);
            } catch (RemoteException e) {
                e.printStackTrace ();
            }

        }
    }

    private IMessageCallback2 messageCallback2 = new IMessageCallback2 (this);

    static class IMessageCallback2 extends IMessageCallback.Stub {

        private final WeakReference<Activity> mActivity;
        private TextView messageTx;

        public IMessageCallback2 (Activity activity) {

            mActivity = new WeakReference<Activity> (activity);
        }

        @Override
        public void onMessageCallback (String msg) throws RemoteException {

            Activity activity = mActivity.get ();
            if (activity != null) {


                messageTx = (TextView) activity.findViewById (R.id.messageTx);
                messageTx.setText (msg);
            }
        }
    }


    private Intent getExplicitIntent (Context context, Intent implicitIntent) {
        // Retrieve all services that can match the given intent
        PackageManager pm = context.getPackageManager ();
        List<ResolveInfo> resolveInfo = pm.queryIntentServices (implicitIntent,
                                                                0);
        // Make sure only one match was found
        if (resolveInfo == null || resolveInfo.size () != 1) {
            return null;
        }
        // Get component info and create ComponentName
        ResolveInfo serviceInfo = resolveInfo.get (0);
        String packageName = serviceInfo.serviceInfo.packageName;
        String className = serviceInfo.serviceInfo.name;
        ComponentName component = new ComponentName (packageName,
                                                     className);
        // Create a new intent. Use the old one for extras and such reuse
        Intent explicitIntent = new Intent (implicitIntent);
        // Set the component to be explicit
        explicitIntent.setComponent (component);
        return explicitIntent;
    }

}
